package service

import (
	"context"
	"errors"
	"github.com/minio/minio-go/v7"
	"github.com/rs/zerolog"
	"github.com/spf13/cast"
	"mime/multipart"
	"net/http"
	"ruoyi-go-echo-ddd/internal/infrastructure/utils"
)

type MinioService struct {
	Client *minio.Client
}

func NewMinioService(c *minio.Client) *MinioService {
	return &MinioService{
		Client: c,
	}
}

func (s *MinioService) Upload(ctx context.Context, form *multipart.Form, bucketName string) (string, error) {

	// 获取所有文件
	files := form.File
	// 获取所有字符串参数
	fields := form.Value

	zerolog.DefaultContextLogger.Debug().Msgf("获取的表单文件参数===%v，字符串参数===%v", files, fields)

	if len(files) == 0 {
		zerolog.DefaultContextLogger.Error().Msgf("未获取到上传文件: %+v", files)
		return "", errors.New("未获取到上传信息")
	}

	var fileHeader *multipart.FileHeader
	for _, values := range files {
		if len(values) > 0 {
			// 取第一个文件
			fileHeader = values[0]
			break
		}
	}

	if fileHeader == nil {
		zerolog.DefaultContextLogger.Error().Msg("未获取到上传文件")
		return "", errors.New("未获取到上传信息")
	}

	forever := false
	for _, values := range fields {
		if len(values) > 0 {
			forever = cast.ToBool(values[0])
			break
		}
	}

	// 调用上传
	url, err := utils.HandlerUpload(ctx, s.Client, fileHeader, bucketName, forever)
	if err != nil {
		return "", err
	}
	return url, nil
}

func (s *MinioService) UploadFiles(ctx context.Context, form *multipart.Form, bucketName string) ([]string, error) {
	list, err := utils.HandlerParallelUpload(ctx, s.Client, form, bucketName)
	if err != nil {
		return nil, err
	}

	return list, nil
}

func (s *MinioService) UploadPrefix(ctx context.Context, form *multipart.Form, bucketName string) ([]string, error) {
	list, err := utils.HandlerParallelUpload(ctx, s.Client, form, bucketName)
	if err != nil {
		return nil, err
	}

	return list, nil
}

func (s *MinioService) Delete(ctx context.Context, bucketName string, list []string) (int64, error) {
	if err := utils.RemoveObjList(ctx, s.Client, bucketName, list); err != nil {
		return 0, err
	}
	return int64(len(list)), nil
}

func (s *MinioService) GetStatObject(ctx context.Context, bucketName, objectName string) (minio.ObjectInfo, error) {
	return utils.GetStatObject(ctx, s.Client, bucketName, objectName)
}

func (s *MinioService) FileInputByte(ctx context.Context, writer http.ResponseWriter, bucketName string, objectName, dstPath string, size int64) ([]byte, int64, error) {
	return utils.GetObjByte(ctx, writer, s.Client, bucketName, objectName, dstPath, size)
}

func (s *MinioService) DownloadObjectWithResume(ctx context.Context, bucketName, objectName, dstPath string, partSize int64) error {
	return utils.DownloadObjectWithResume(ctx, s.Client, bucketName, objectName, dstPath, partSize)
}

func (s *MinioService) DownloadResponseWithResume(ctx context.Context, w http.ResponseWriter,
	bucketName, objectName string, cacheSize int64) error {
	_, err := utils.StreamObjectToWriter(ctx, w, s.Client, bucketName, objectName, cacheSize)
	return err
}

func (s *MinioService) DownloadObjectListToZip(ctx context.Context, w http.ResponseWriter, bucketName string, objectList []string, cacheSize int64) error {
	return utils.StreamObjectListToZip(ctx, w, s.Client, bucketName, objectList, cacheSize)
}

func (s *MinioService) DownloadObjectListToZipParallel(ctx context.Context, w http.ResponseWriter, bucketName string, objectList []string, cacheSize, concurrency int64) error {
	return utils.ParallelDownloadToZipConcurrent(ctx, w, s.Client, bucketName, objectList, cacheSize, concurrency)
}
